package main;

import java.io.IOException;
import java.math.BigInteger;
import java.util.LinkedList;

import message.Cipher;
import message.Conversion;
import message.FileIO;
import crypto.Keys;

import util.Domain;
import util.Point;

public class Main {
		
	private static Domain domain = null;
	private static Keys keyPair = null;
	private static String message = null;
	private static Cipher cipher = null;
	
	public static void loadDomainFromFile() {

		try {
			String filename = FileIO.readLineFromPrompt("Enter the filename of the domain parameters\n>");
			loadDomainFromFile(filename);
//			domain = new Domain(filename);
//			keyPair = new Keys(domain);
//			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void loadDomainFromFile(String filename) {
		domain = new Domain(filename);
		keyPair = new Keys(domain);
	}
	
//	public static boolean enterDomainValues() {
//		// TODO: implement
//		return false;
//	}
	
	public static boolean generateKeys() {
		if (keyPair == null) {
			return false;
		}
		return keyPair.generateKeyPairs();
	}
	
	public static boolean loadKeys() {
		if (keyPair == null) {
			return false;
		}
		return keyPair.loadKeyPair();
	}
	
	public static boolean saveKeys() {
		if (keyPair == null || !keyPair.hasValidKeys()) {
			return false;
		}
		return keyPair.saveKeyPair();
	}
	
	public static boolean loadMessageIntoBuffer() {
		String filename;
		try {
			filename = FileIO.readLineFromPrompt("Enter the filename of the Message\n>");
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			return false;
		}
		
		try {
			message = FileIO.readMessageFromFile(filename);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public static void readMessageFromPrompt() {
		try {
			message = FileIO.readMessageFromPrompt();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void outputMessage() {
		if (message == null) {
			return;
		}
		System.out.println("-- Start --");
		System.out.println(message);
		System.out.println("-- End --");
	}
	
	public static boolean saveMessage() {
		if (message == null) {
			return false;
		}
		String filename;
		try {
			filename = FileIO.readLineFromPrompt("Enter the filename for the Message\n>");
			FileIO.writeMessageToFile(message, filename);
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			return false;
		}
	}
	
	public static boolean encryptMessage() {
		if (keyPair == null || message == null) {
			return false;
		}
		Point receiverKey = Keys.loadPublicKey();
		String numberString;
		try {
			numberString = FileIO.readLineFromPrompt("Give a number k, such that 2^k is high for probability of embedding the message.\n" +
					"A higher number can mean longer waiting time (1000 recommended).\n>");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		BigInteger k = new BigInteger(numberString);
		cipher = Conversion.messageToCipher(message, keyPair, receiverKey, k);
		return true;
	}
	
	public static boolean signCipher() {
		if (keyPair == null || cipher == null) {
			return false;
		}
		try {
			Conversion.signCipher(cipher, keyPair);
		} catch (IllegalArgumentException e) {
			return false;
		}
		return true;
	}
	
	public static boolean saveCipher() {
		if (cipher == null) {
			return false;
		}
		String filename;
		try {
			filename = FileIO.readLineFromPrompt("Enter the filename for the Cipher\n>");
			FileIO.writeCipherToFile(cipher, filename);
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			return false;
		}
	}
	
	public static boolean loadCipherIntoBuffer() {
		String filename;
		try {
			filename = FileIO.readLineFromPrompt("Enter the filename of the Cipher\n>");
			cipher = FileIO.readCipherFromFile(filename);
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			return false;
		}
	}
	
	public static boolean verifyKeyOwner() {
		if (cipher == null)
			return false;
		Point publicKey = Keys.loadPublicKey();
		if (publicKey.isPointOfInfinity()) {
			return false;
		}
		return Conversion.verifyPublicKeyOwner(cipher, publicKey);
	}
	
	public static boolean decryptCipher() {
		if (keyPair == null || cipher == null) {
			return false;
		}
		message = Conversion.cipherToMessage(cipher, keyPair);
		return true;
	}
		
	public static boolean verifySignature() {
		if (keyPair == null || cipher == null) {
			return false;
		}
		return Conversion.verifyCipher(cipher, keyPair);
	}
	
	
	
	public static void main(String args[]) {
		
		loadDomainFromFile("DomainParameters.txt");
		do {
			System.out.println("What do you want to do?");
			System.out.println(" 0: Load domain parameter from file");
			System.out.println(" 1: Generate keys");
			System.out.println(" 2: Load and verify keys");
			System.out.println(" 3: Save keys to file");
			System.out.println(" 4: Read Message from file");
			System.out.println(" 5: Read Message from prompt");
			System.out.println(" 6: Encrypt Message");
			System.out.println(" 7: Sign Cipher");
			System.out.println(" 8: Load Cipher from file");
			System.out.println(" 9: Verify Key Owner");
			System.out.println("10: Verify Signature");
			System.out.println("11: Decrypt Cipher");
			System.out.println("12: Print Message");
			System.out.println("13: Save Message to file");
			System.out.println("14: Save Cipher to file");
			System.out.println(" e: Exit");
			
			String input = new String();
			try {
				input = FileIO.readLineFromPrompt("\n>");
			} catch (IOException e) {
				System.err.println(e.getLocalizedMessage());
			}
			
			if (input.isEmpty()) {
				continue;
			}
			
			if (input.charAt(0) == 'e') {
				break;
			}
			
			int selection = -1;
			try {
				selection = Integer.parseInt(input);
			} catch (NumberFormatException e) {
				System.err.println(e.getLocalizedMessage());
			}
			
			boolean result = false;
			boolean hasResult = false;
			switch (selection) {
			case 0: loadDomainFromFile(); break;
			case 1: result = generateKeys(); hasResult = true; break;
			case 2: result = loadKeys(); hasResult = true; break;
			case 3: result = saveKeys(); hasResult = true; break;
			case 4: result = loadMessageIntoBuffer(); hasResult = true; break;
			case 5: readMessageFromPrompt(); break;
			case 6: result = encryptMessage(); hasResult = true; break;
			case 7: result = signCipher(); hasResult = true; break;
			case 8: result = loadCipherIntoBuffer(); hasResult = true; break;
			case 9: result = verifyKeyOwner(); hasResult = true; break;
			case 10: result = verifySignature(); hasResult = true; break;
			case 11: result = decryptCipher(); hasResult = true; break;
			case 12: outputMessage(); break;
			case 13: result = saveMessage(); hasResult = true; break;
			case 14: result = saveCipher(); hasResult = true; break;
			}
			
			if (hasResult) {
				System.out.println("The method was successful or had a positive result: " + result + "\n\n");
			}
		
		} while (true);
	}

}
